use std::{rc::Rc, cell::RefCell};

use crate::{instructions::base::Instruction, rtda::Frame};


// Multiply double
#[derive(Debug, Default)]
pub struct DMUL {}

impl Instruction for DMUL {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let v2 = stack.borrow_mut().pop_double();
        let v1 = stack.borrow_mut().pop_double();
        let result = v1 * v2;
        stack.borrow_mut().push_double(result);
    }
}

// Multiply float
#[derive(Debug, Default)]
pub struct FMUL {}

impl Instruction for FMUL {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let v2 = stack.borrow_mut().pop_float();
        let v1 = stack.borrow_mut().pop_float();
        let result = v1 * v2;
        stack.borrow_mut().push_float(result);
    }
}


// Multiply int
#[derive(Debug, Default)]
pub struct IMUL {}

impl Instruction for IMUL {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let v2 = stack.borrow_mut().pop_int();
        let v1 = stack.borrow_mut().pop_int();
        let result = match v1.checked_mul(v2) {
            Some(v) => v,
            None => (v1 as i128 * v2 as i128) as i32
        };
        stack.borrow_mut().push_int(result);
    }
}

// Multiply long
#[derive(Debug, Default)]
pub struct LMUL {}

impl Instruction for LMUL {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let v2 = stack.borrow_mut().pop_long();
        let v1 = stack.borrow_mut().pop_long();
        let result = v1 * v2;
        stack.borrow_mut().push_long(result);
    }
}